/*****************************************************************************
*                     Organizacion de Datos - 75.06                          *
*                         Catedra Lic. Servetto                              *
*            Facultad de Ingenieria - Universidad de Buenos Aires            *
******************************************************************************/ 

#include "Archivo.h"
#include "Operacion.h"
#include "ConversorDeStreams.h"
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

namespace Comun
{
	
	/***************************************/
	/* DESDE DATOS CONCRETOS HACIA STREAMS */
	/***************************************/

	void ConversorDeStreams::ClaseAStream(Clase *clase, stringstream *salida)
	{
		*salida << *clase->NombreClase << endl;
		
		*salida << clase->Miembros->size() << endl;
		for(IteradorDeAtributos i = clase->Miembros->begin(); i != clase->Miembros->end(); ++i)
		{
			Atributo atributo = *i;
			*salida << atributo.Nombre.c_str() << endl;
			*salida << ParserDeTipoRegistro::Parsear(atributo.Tipo).c_str() << endl;
			//*salida << atributo.Valor.c_str() << endl;
		}		
	}

	void ConversorDeStreams::CondicionAStream(CondicionCompuesta *condicion, stringstream *salida)
	{
		ConversorDeStreams::TipoSimboloAStream(condicion->Simbolo,salida);
		*salida << condicion->Subcondiciones.size() << endl;	

		for(list<Condicion*>::iterator i = condicion->Subcondiciones.begin(); i != condicion->Subcondiciones.end(); ++i)
		{
			Condicion* cond = *i;
			ConversorDeStreams::TipoSimboloAStream(cond->Simbolo,salida);
			*salida << cond->ValorCondicion.Nombre << endl;
			*salida << ParserDeTipoRegistro::Parsear( cond->ValorCondicion.Tipo).c_str() << endl;
			*salida << cond->ValorCondicion.Valor << endl;
		}	

	}

	void ConversorDeStreams::ListaDatosAStream(list<ClaveValor> *datos, stringstream *salida)
	{
		*salida << datos->size() << endl;
		for(list<ClaveValor>::iterator i = datos->begin(); i != datos->end(); ++i)
		{
			*salida << i->Clave.c_str() << endl;			
			*salida << i->Valor.c_str() << endl;
		}
	}

	void ConversorDeStreams::ListaMiembrosAStream(list<string> *miembros, stringstream *salida)
	{
		*salida << miembros->size() << endl;
		for(list<string>::iterator i = miembros->begin(); i != miembros->end(); ++i)
		{
			*salida << *i << endl;			
		}
	}



	Clase* ConversorDeStreams::StreamAClase(stringstream *entrada)
	{
		Clase* clase = new Clase();
		clase->NombreClase = new string(ConversorDeStreams::StreamACadena(entrada));

		// Leo los atributos del grupo del stream.
		int cantidadAtributos;
		*entrada >> cantidadAtributos;
		for(int i = 0; i < cantidadAtributos; ++i)
		{
			Atributo& atributo = *(new Atributo());
			*entrada >> atributo.Nombre;
			string tipoAtributo;
			*entrada >> tipoAtributo;
			atributo.Tipo = ParserDeTipoRegistro::Parsear(tipoAtributo);
			//getline(*entrada, atributo.Valor); // Emula un get() de un solo caracter;
			//getline(*entrada, atributo.Valor);
			clase->Miembros->push_back(atributo);
		}		

		return clase;
	}

	list<ClaveValor>* ConversorDeStreams::StreamAListaDatos(stringstream *entrada)
	{
		list<ClaveValor>* datos = new list<ClaveValor>();

		int cantidadDatos;
		*entrada >> cantidadDatos;
		
		string aux;
		getline(*entrada,aux);
		for(int i = 0; i < cantidadDatos; ++i)
		{
			ClaveValor* cv = new ClaveValor();
			
			getline(*entrada,cv->Clave); 
			getline(*entrada,cv->Valor); 

			datos->push_back(*cv);

			delete cv;
		}

		return datos;
	}

	list<string>* ConversorDeStreams::StreamAListaDeMiembros(stringstream *entrada)
	{
		list<string>* datos = new list<string>();

		int cantidadMiembros;
		*entrada >> cantidadMiembros;
		
		for(int i = 0; i < cantidadMiembros; ++i)
		{
			datos->push_back(ConversorDeStreams::StreamACadena(entrada));			
		}

		return datos;
	}

	CondicionCompuesta* ConversorDeStreams::StreamACondicion(std::stringstream *entrada)
	{
		CondicionCompuesta* condicion;
		TipoSimbolo simbolo = StreamATipoSimbolo(entrada);
		
		if (simbolo == And)
			condicion = new CondicionCompuestaAND();
		else if (simbolo == Or)
			condicion = new CondicionCompuestaOR();
		else
		{
			cerr << "Comun->ConversorDeStreamsConsulta.cpp->ConversorDeStreams::StreamACondicion(stringstream* entrada)" << endl << "Simbolo invalido para una condicion compuesta." << endl;
			throw new exception();
		}

		int cantidadSubCondiciones;
		*entrada >> cantidadSubCondiciones;

		for(int i = 0; i < cantidadSubCondiciones; ++i)
		{
			Condicion* c;
			TipoSimbolo s = StreamATipoSimbolo(entrada);
			switch(s)
			{
			case Igual:
				c = new CondicionIgual();
				break;
			case Mayor:
				c = new CondicionMayor();
				break;
			case MayorIgual:
				c = new CondicionMayorIgual();
				break;
			case Menor:
				c = new CondicionMenor();
				break;
			case MenorIgual:
				c = new CondicionMenorIgual();
				break;
			}

			Atributo* atributo = new Atributo();
			*entrada >> atributo->Nombre;
			string tipoAtributo;
			*entrada >> tipoAtributo;
			atributo->Tipo = ParserDeTipoRegistro::Parsear(tipoAtributo);
			getline(*entrada, atributo->Valor); // Emula un get() de un solo caracter;
			getline(*entrada, atributo->Valor);
			c->ValorCondicion = *atributo;

			condicion->Subcondiciones.push_back(c);

			delete atributo;

		}

		return condicion;
	}


	/// Inserta la representacion de un operacion en la salida estandar.
	/// @param operacion Operacion a guardar en el stream.
	/// @param salida Stream donde se guardara dato.
	void ConversorDeStreams::OperacionAStream(OperacionConsulta operacion, stringstream* salida)
	{
		*salida << ParserDeOperacionConsulta::Parsear(operacion).c_str() << endl;
	};

	/// Inserta la representacion de un operacion en la salida estandar.
	/// @param operacion Operacion a guardar en el stream.
	/// @param salida Stream donde se guardara dato.
	void ConversorDeStreams::TipoSimboloAStream(TipoSimbolo simbolo, stringstream* salida)
	{
		*salida << ParserTipoSimbolo::Parsear(simbolo).c_str() << endl;
	};

		/// Lee la representacion de una operacion de la entrada estandar y la devulve.
	/// @param entrada Stream con los datos de entrada.
	/// @return Operacion representada en el stream.
	OperacionConsulta ConversorDeStreams::StreamAOperacionConsulta(stringstream* entrada)
	{
		// Leo la entrada como string.
		string resultado;
		*entrada >> resultado;
		
		// Parseo la operacion y la devuelvo.
		return ParserDeOperacionConsulta::Parsear(resultado);
	};

	/// Lee la representacion de una operacion de la entrada estandar y la devulve.
	/// @param entrada Stream con los datos de entrada.
	/// @return Operacion representada en el stream.
	TipoSimbolo ConversorDeStreams::StreamATipoSimbolo(std::stringstream *entrada)
	{
		// Leo la entrada como string.
		string resultado;
		*entrada >> resultado;
		
		// Parseo la operacion y la devuelvo.
		return ParserTipoSimbolo::Parsear(resultado);
	};
	
}

